[GitHub]保護ブランチへのマージ向けPR作成をworkflow_dispatchで手軽くやってみた
はじめに
何も弄ってないのにいきなり動作が変わっていると流石に慌てるものだと思ったこの頃です。
Actionsを利用してのCDを実施していたところ、普段特に問題がなかった箇所でエラーが発生していました。
remote: error: GH006: Protected branch update failed for refs/heads/master. remote: error: Waiting on code owner review from haoyayoi and/or xxxxxx. To https://github.com/xxxxxxxx/yyyyyyy ! [remote rejected] master -> master (protected branch hook declined)
何かやらかしがコミットに入っていたのかと思いましたが、動作を追ってみたところWorkflow内で行われているnpm version
によるCommitとPushが原因でした。Tokenは勿論設定済み。「あれ、動いてたはずなんだけど」という思いの元に検索してみたものの、そういう仕様ですとしか言えない記述ばかりが見つかる状態でした。
とりあえずはProtectedを逐一外すことで対処しましたが、事故の発生は不可避です。GitHubのフォーラム等を辿った上で行き着いたActions設定を交えて、ログとして書いておきます。
ブランチの保護には例外が通じない
GitHubでは想定しない変更を抑えるためにBranchを保護することができます。勝手に書き換えられることを防ぐ意味でも重要です。ただ、Actionsを使う上ではやや面倒な状態が成立することもあります。
主に、Workflow上で保護ブランチに直接のCommitやPushを発生させたい場合。そんなことあるっけ、と思われそうなのも確かですが、更新に伴うバージョン番号のインクリメントがありがちなケースです。「作業ブランチをMergeさせるタイミングでやればいいじゃないか」という声も聞こえてきそうです。
まぁ実際そうなのですが、細かい修正をマイナー、本番反映させるタイミングでメジャーバージョンを更新させるようなケースになると話が変わってきます。単純なバージョンのインクリメントにもPull-Request、設定によってはReviewが必要になるわけです。
なお、ブランチの保護を反映のタイミングだけ解除するという手段も見かけました。
I was able to create a workflow that temporarily disables the branch protection and then enables it again. This works fine if you don’t have multiple pull requests merged to master at the same time. And of course this means there is no branch protection for a few seconds.
設定変更についてはいつ行われたのか直ぐには判別し難いため、何か発生した場合に調査が非常に難しくなり、正直おすすめはできません。
以下のスレッドにはGitHub CommunityのStaffからのコメントがあり、手順として妥当なものと思えました。
If we enabled GitHub Actions to push to a protected branch then any collaborator in your repo could push any code to any branch they wanted simply by creating a branch and coding the workflow to push to to some other branch. Using the REST api to merge the PR is the right flow and overtime hopefully there will be actions that make that easier to implement.
ということで、作業用ブランチ作りつつPRも発行し、mergeした後はお好みに処理するためのWorkflowを作ってみました。
Merge用PR発行を機械的に行うWorkflow
今回のポイントは以下の通り。
- workflow_dispatchを介してPRを作成する
- うっかりworkflow_dispatchを多重実行した場合でも有効なPRは一つだけ
作業ブランチを固定にすることで多重実行してしまってもエラーで中断させます。
PR作成用
on: workflow_dispatch: branches: - master jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: ref: ${{ github.sha }} - name: Set up Node uses: actions/setup-node@v1 with: node-version: '10.x' - name: Git config run: | git config --global user.email "xxxxxxx@yyyyyy" git config --global user.name "GitHub Actions" - name: Create Release id: create_branch run: | git checkout -b release git push --set-upstream origin release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Update major version id: update_major_version run: | mkdir .git echo "version_no=$(npm version minor --no-git-tag-version)" >> $GITHUB_ENV npm version minor git push env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} working-directory: cdk - name: Create release PR id: create_release_pr uses: peter-evans/create-pull-request@v3 with: branch: release base: master title: "Deploy ${{env.version_no}}" draft: false
npm version
に対して--no-git-tag-version
とオプションを入れていますが、これはCommitを発生させずにバージョン番号を取るためです。このタイミングではCommitが発生しなかったために次の行にてCommit目的で再実行していますが、万が一を考えて前の行ではCommitを明示的に回避させています。
Merge後のお好み用
delete-merged-branch
をブランチ削除用に使っています。PR作成に用いたcreate-pull-request
にもdelete-branch
なるオプションがあるのですが、同じフロー内でPRのcloseも扱わない場合には動作は期待できないようです。
on: pull_request: branches: - master types: [closed] jobs: test: runs-on: ubuntu-latest if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'release' steps: - uses: actions/checkout@v2 with: ref: ${{ github.sha }} - name: delete branch uses: SvanBoxel/delete-merged-branch@main env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Set up Node uses: actions/setup-node@v1 with: node-version: '10.x' - name: Hello run: echo "Hello"
実際に書いてみると本当に単純なワークフローなんですが、これの確認が結構手間取ります。
実際に動かしてみる
ActionsからPR作成用のWorkflowを実行します。
実行後、Workflowが完了するまで暫く待ちます。
マージします。
Deploy用のWorkflowが動作しました。
Workflow完了後、PRをみてみると作業ブランチの削除も確認できました。
多重実行時
作業ブランチが固定になっているおかげで、ブランチ作成時に重複で失敗して止まっていました。狙い通りです。
あとがき
npm version
で失敗するようになった状況の原因が未だにわかっていないのですが、そもそも出来ていたのがおかしいと考えることにしました。
PR作成用のworkflow_dispatch起点であるWorkflowと、merge後によろしくやってくれるWorkflowの組み合わせは流石に都合よく落ちておらず、やむを得ず作ってみました。意外とベースはシンプルにできた感じです。ベースの動作は確認済みのため、作るのが面倒な場合には今回のサンプルをおすすめします。